#include "../include/head.h"

// 服务端当前目录
//char serverDir[256] = "~";
char *serverDir;
int exitPipe[2];

void handler(int signum){
    printf("signum = %d\n", signum);
    write(exitPipe[1],"1",1);
}


int main()
{
    serverDir = (char *)calloc(1024, sizeof(char));
    strcpy(serverDir,"../UserDir");
    pipe(exitPipe);// 这个pipe要fork之前
    if(fork())
    {
        //只有父进程
        close(exitPipe[0]);
        signal(SIGUSR1,handler);
        int pid = getpid();
        printf("父进程pid = %d\n", pid);
        wait(NULL);
        printf("Parent is going to exit!\n");
        exit(0);
    }

    close(exitPipe[1]);

    //初始化三个队列
    //初始化三个共享资源结构体
    shareRes_t arges[3];

    //初始化pthread_Data
    pthread_data_t pthread_data;
    init_pthread_data(&pthread_data,3);

    taskQueue_t queues[2];
    for(int i =0;i<2;i++)
    {
        init_queue(&queues[i]);
    }

    //初始化clientinfo
    Client_info client_info[1024];
    for(int i = 0;i<1024;i++)
    {
        client_info[i].belongs_to_userid = -1;
        client_info[i].now_path_id = 0;
    }

    // 初始化clientinfo锁
    pthread_mutex_t mutex_client_info = PTHREAD_MUTEX_INITIALIZER;

    // 初始化mysql锁
    pthread_mutex_t mysql_mutex = PTHREAD_MUTEX_INITIALIZER;

    //初始化标志位
    int exitFlag = 0;
    
    int sockfd = initTcp("127.0.0.1","33333");
    int epfd = epoll_create(1);
    printf("主线程epfd = %d\n", epfd);
    epollAdd(epfd, sockfd, 0); // 0水平触发，1边缘触发
    epollAdd(epfd,exitPipe[0],1);

    // 长命令队列 锁和条件变量
    pthread_mutex_t long_queue_mutex;
    pthread_cond_t long_queue_cond;
    pthread_mutex_init(&long_queue_mutex, NULL);
    pthread_cond_init(&long_queue_cond,NULL);
    // 短命令队列 锁和条件变量
    pthread_mutex_t short_queue_mutex;
    pthread_cond_t short_queue_cond;
    pthread_mutex_init(&short_queue_mutex, NULL);
    pthread_cond_init(&short_queue_cond,NULL);
    //创建线程池
    makeworker(arges, &pthread_data, client_info, &exitFlag, &mutex_client_info, &mysql_mutex, &long_queue_mutex, &long_queue_cond,&short_queue_mutex,&short_queue_cond, queues, &epfd);

    // MYSQL连接
    pthread_mutex_lock(&mysql_mutex);
    MYSQL *mysql = mysql_init(NULL);
    /* MYSQL *connect_ret = mysql_real_connect(mysql, "localhost", "root", "031178514530", "user_base", 0, NULL, 0); */
    MYSQL *connect_ret = mysql_real_connect(mysql, "localhost", "admin", "123", "user_base", 0, NULL, 0);
    /* MYSQL *connect_ret = mysql_real_connect(mysql, "localhost", "admin", "210710", "user_base", 0, NULL, 0); */
    if(connect_ret == NULL)
    {
        fprintf(stderr, "%s:%s\n", "mysql connect", mysql_error(connect_ret));
        exit(-1);
    }
    pthread_mutex_unlock(&mysql_mutex);

    

    int maxIndex = 0;

    struct epoll_event readySet[1024];
    TimeWheel_t* timewheel=TimeWheel_create(); //初始化时间轮片

    ResponsePackage* user_response=(ResponsePackage*)calloc(1,sizeof(ResponsePackage));

    while(1)
    {
        int readyNum = epoll_wait(epfd,readySet,1024,1000);
        SET_t* newset=(SET_t*)calloc(1,sizeof(SET_t));

        for(int i = 0; i<readyNum; ++i)
        {
            if(readySet[i].data.fd == sockfd)
            {   
                int netfd = accept(sockfd,NULL,NULL);
                printf("accept:%d\n",netfd);
                maxIndex = netfd > maxIndex ? netfd:maxIndex;
                epollAdd(epfd, netfd, 0);
                //添加到时间轮片
                int idx=set_insert(newset,netfd);
                // printf("当前新集合的netfd个数:%d\n",idx);
            }
            else if(readySet[i].data.fd == exitPipe[0])
            {
                pthread_mutex_lock(&mutex_client_info);
                exitFlag =1;
                for(int i = 0;i<pthread_data.workernum;i++)
                {
                    pthread_cond_broadcast(arges[i].cond);
                }
                pthread_mutex_unlock(&mutex_client_info);
                for(int i = 0; i<pthread_data.workernum;i++)
                {
                    pthread_join(pthread_data.ptidarr[i],NULL);
                }
                exit(0);

            }
            else
            {

                for(int j =3;j<=maxIndex;++j)
                {
                    if(readySet[i].data.fd == j)
                    {

                        // 添加到时间轮片
                        int idx=set_insert(newset,j);
                        // printf("当前新集合的netfd个数:%d\n",idx);

                        MSG_TYPE type;
                       
                        int recvret = recvn(j,&type,sizeof(type),NULL);
                        if(!ErrCheck_ClientClose(recvret,j,epfd,&mutex_client_info,client_info)){continue;}

                        // printf("netfd = %d,main epoll_wait type = %d\n", j,type);

                        if(type == USER_LOGIN||type == USER_REGI||type == USER_LOGIN2)
                        {
                            if (type == USER_LOGIN)
                            {
                                char name_buf[512] = {0};

                                memset(user_response, 0, sizeof(ResponsePackage));

                                int ret = recvn(j,&user_response->args_len, sizeof(int), NULL);
                                if(!ErrCheck_ClientClose(ret,j,epfd,&mutex_client_info,client_info)){continue;}

                                ret = recvn(j, user_response->args_val, user_response->args_len, NULL);
                                if(!ErrCheck_ClientClose(ret,j,epfd,&mutex_client_info,client_info)){continue;}

                                memcpy(name_buf, user_response->args_val, user_response->args_len);
                                // printf("用户名为：%s\n", name_buf);

                                char setting[512] = {0};
                                int res = user_login1(mysql, name_buf,setting);

                                if(res == -1)
                                {
                                    memset(user_response, 0, sizeof(ResponsePackage));

                                    user_response->type = L_R_ERR;

                                    memcpy(user_response->args_val, "用户名不存在！", 22);
                                    user_response->args_len = strlen(user_response->args_val);

                                    send(j, &user_response->type, sizeof(int), MSG_NOSIGNAL);
                                    send(j, &user_response->args_len, sizeof(int), MSG_NOSIGNAL);
                                    send(j, user_response->args_val, user_response->args_len, MSG_NOSIGNAL);
                                }
                                if(res == 0)
                                {
                                    memset(user_response, 0, sizeof(ResponsePackage));

                                    user_response->type = L_R_SUCCESS;

                                    user_response->args_len = strlen(setting);
                                    memcpy(user_response->args_val, setting, user_response->args_len);

                                    send(j, &user_response->type, sizeof(int), MSG_NOSIGNAL);
                                    send(j, &user_response->args_len, sizeof(int), MSG_NOSIGNAL);
                                    send(j, user_response->args_val, user_response->args_len, MSG_NOSIGNAL);
                                }
                            }
                            else if (type == USER_LOGIN2)
                            {
                                memset(user_response, 0, sizeof(ResponsePackage));

                                int ret = recvn(j, &user_response->args_len, sizeof(int), NULL);
                                if(!ErrCheck_ClientClose(ret,j,epfd,&mutex_client_info,client_info)){continue;}

                                ret = recvn(j, user_response->args_val, user_response->args_len, NULL);
                                if(!ErrCheck_ClientClose(ret,j,epfd,&mutex_client_info,client_info)){continue;}

                                // printf("%s\n", user_response->args_val);
                                char name_buf[512] = {0};
                                char ciphertest_buf[512] = {0};

                                char *p=strtok(user_response->args_val," ");
                                memcpy(name_buf, p, strlen(p));
                                // printf("name = %s\n", name_buf);

                                p = strtok(NULL, " ");
                                memcpy(ciphertest_buf, p, strlen(p));
                                // printf("cip = %s\n", ciphertest_buf);

                                int user_path_id;
                                int user_id;

                                int res = user_login2(mysql,name_buf,ciphertest_buf,&user_path_id,&user_id);

                                if(res == -1)
                                {
                                    memset(user_response, 0, sizeof(ResponsePackage));

                                    user_response->type = L_R_ERR;

                                    memcpy(user_response->args_val, "密码输入错误！", 22);
                                    user_response->args_len = strlen(user_response->args_val);

                                    send(j, &user_response->type, sizeof(int), MSG_NOSIGNAL);
                                    send(j, &user_response->args_len, sizeof(int), MSG_NOSIGNAL);
                                    send(j, user_response->args_val, user_response->args_len, MSG_NOSIGNAL);
                                }
                                if(res == 0)
                                {
                                    memset(user_response, 0, sizeof(ResponsePackage));

                                    user_response->type = L_R_SUCCESS;

                                    pthread_mutex_lock(&mutex_client_info);
                                    client_info[j].now_path_id = user_path_id;
                                    client_info[j].belongs_to_userid = user_id;
                                    pthread_mutex_unlock(&mutex_client_info);

                                    user_response->args_len = 0;

                                    send(j, &user_response->type, sizeof(int), MSG_NOSIGNAL);
                                    send(j, &user_response->args_len, sizeof(int), MSG_NOSIGNAL);
                                }
                            }
                            else if(type == USER_REGI)
                            {
                                char name_buf[512] = {0};
                                char setting_buf[512] = {0};
                                char ciphertest_buf[512] = {0};

                                memset(user_response, 0, sizeof(ResponsePackage));

                                int ret = recvn(j, &user_response->args_len, sizeof(int), NULL);
                                if(!ErrCheck_ClientClose(ret,j,epfd,&mutex_client_info,client_info)){continue;}
                                
                                ret = recvn(j, user_response->args_val, user_response->args_len, NULL);
                                if(!ErrCheck_ClientClose(ret,j,epfd,&mutex_client_info,client_info)){continue;}
                                
                                char *p=strtok(user_response->args_val," ");
                                memcpy(name_buf, p, strlen(p));
                                // printf("name = %s\n", name_buf);

                                p = strtok(NULL, " ");
                                memcpy(setting_buf, p, strlen(p));
                                // printf("setting = %s\n", setting_buf);

                                p = strtok(NULL, " ");
                                memcpy(ciphertest_buf, p, strlen(p));
                                // printf("setting = %s\n", ciphertest_buf);

                                int user_path_id;
                                int user_id;

                                int res;

                                res = user_registration(mysql,name_buf,setting_buf,ciphertest_buf,&user_path_id,&user_id);
                            
                                memset(user_response, 0, sizeof(ResponsePackage));

                                if(res != 0)
                                {
                                    user_response->type =L_R_ERR;
                                }
                                else if(res == 0)
                                {
                                    user_response->type = L_R_SUCCESS;
                                    // 如果登录或者注册成功，再正式修改client_info
                                    pthread_mutex_lock(&mutex_client_info);
                                    client_info[j].now_path_id = user_path_id;
                                    client_info[j].belongs_to_userid = user_id;
                                    pthread_mutex_unlock(&mutex_client_info);
                                }

                                if (res == -2)
                                {
                                    memcpy(user_response->args_val, "用户名不可重复！", 25);
                                    user_response->args_len = strlen(user_response->args_val);
                                }
                                else
                                {
                                    user_response->args_len = 0;
                                }

                                send(j, &user_response->type, sizeof(int), MSG_NOSIGNAL);
                                send(j, &user_response->args_len, sizeof(int), MSG_NOSIGNAL);
                                if(user_response->args_len != 0)
                                {
                                    send(j, user_response->args_val, user_response->args_len, MSG_NOSIGNAL);
                                }
                            }                        
                        }
                        else 
                        {
                            taskNode_t* task = (taskNode_t*)calloc(1,sizeof(taskNode_t));

                            task->type = type;
                            if(type == C_OP_GETS_BEGIN || type == C_OP_PUTS_BEGIN)
                            {
                                // 从新集合和时间轮中删除要执行下载的netfd
                                set_delete(newset, j);
                                TimeWheel_deletefd(timewheel, j);

                                int args_len;
                                int recvret = recvn(j,&args_len,sizeof(int),NULL);
                                if(!ErrCheck_ClientClose(recvret,j,epfd,&mutex_client_info,client_info)){continue;}

                                // printf("args_len = %d\n", args_len);

                                if(args_len != 0)
                                {
                                    int recvret = recvn(j,task->args,args_len,NULL);
                                    if(!ErrCheck_ClientClose(recvret,j,epfd,&mutex_client_info,client_info)){continue;}
                                }
                                if(type == C_OP_PUTS_BEGIN)
                                {
                                    char argbuf[2048]={0};
                                    memcpy(argbuf,task->args,args_len);
                                    char *addr1=strtok(argbuf," ");//客户端文件的地址
                                    char *addr2=strtok(NULL," ");//服务端要存储的文件的地址
                                    char *md5=strtok(NULL," ");
                                    char *filesizebuf=strtok(NULL," ");
                                    char *father_netfd = strtok(NULL, " ");
                                    char *user_id = strtok(NULL, " ");
                                    char *now_path_id = strtok(NULL, " ");
                                    // printf("now_path_id= %d\n",atoi(now_path_id));

                                    task->netfd = j;
                                    task->father_netfd = atoi(father_netfd);
                                    task->user_id = atoi(user_id);
                                    task->now_path_id = atoi(now_path_id);
                                    task->pNext = NULL;

                                    pthread_mutex_lock(arges[1].mutex_taskqueue);

                                    // printf("开始插入结点！\n");
                                    tail_insert(arges[1].taskqueue, task);
                                    pthread_cond_signal(arges[1].cond);
                                    
                                    pthread_mutex_unlock(arges[1].mutex_taskqueue);
                                    epollDel(epfd, j);
                                }
                                else if(type == C_OP_GETS_BEGIN)
                                {
                                    char argbuf[2048]={0};
                                    memcpy(argbuf,task->args,args_len);
                                    char *addr1=strtok(argbuf," ");//服务端文件的地址
                                    char *addr2=strtok(NULL," ");//客户要存储的文件的地址
                                    char *filesizebuf=strtok(NULL," ");
                                    char *md5=strtok(NULL," ");
                                    char *sendsize =strtok(NULL," ");

                                    // char *father_netfd = strtok(NULL, " ");
                                    // char *user_id = strtok(NULL, " ");
                                    // char *now_path_id = strtok(NULL, " ");
                                    // printf("now_path_id= %d\n",atoi(now_path_id));

                                    task->netfd = j;
                                    task->father_netfd = 0;
                                    task->user_id = 0;
                                    task->now_path_id = 0;
                                    task->pNext = NULL;

                                    pthread_mutex_lock(arges[1].mutex_taskqueue);

                                    // printf("开始插入结点！\n");
                                    tail_insert(arges[1].taskqueue, task);
                                    pthread_cond_signal(arges[1].cond);
                                    
                                    pthread_mutex_unlock(arges[1].mutex_taskqueue);
                                    epollDel(epfd, j);
                                }
                            }

                        else
                        {
                            task->netfd = j;
                            pthread_mutex_lock(&mutex_client_info);
                            task->user_id = client_info[j].belongs_to_userid;
                            task->now_path_id = client_info[j].now_path_id;
                            pthread_mutex_unlock(&mutex_client_info);

                            int args_len;
                            
                            int recvret = recvn(j,&args_len,sizeof(int),NULL);
                            if(!ErrCheck_ClientClose(recvret,j,epfd,&mutex_client_info,client_info)){continue;}

                            printf("args_len = %d\n", args_len);
                            if(args_len != 0)
                            {
                                int recvret = recvn(j,task->args,args_len,NULL);
                                if(!ErrCheck_ClientClose(recvret,j,epfd,&mutex_client_info,client_info)){continue;}
                            }
                            
                            printf("args = %s\n", task->args);
                            task->pNext = NULL;
                            
                            pthread_mutex_lock(arges[0].mutex_taskqueue);
                            // printf("开始插入结点！\n");
                            tail_insert(arges[0].taskqueue, task);
                            pthread_cond_signal(arges[0].cond);
                            pthread_mutex_unlock(arges[0].mutex_taskqueue);
                        }
                        
                        }
                    }
                }
            }
        }
        //将newset加入到时间轮片中，得到delset，将delset集合中的保存的netfd关闭
        SET_t* delset=TimeWheel_insert(timewheel,newset);
        for(int x=0;x<delset->idx;x++){
            //清空用户
            int netfd=delset->arr[x];
            pthread_mutex_lock(&mutex_client_info);
            client_info[netfd].now_path_id = -1;
            client_info[netfd].belongs_to_userid = -1;
            pthread_mutex_unlock(&mutex_client_info);
            epollDel(epfd,netfd);
            close(netfd);
        }

    }
}
